import { useMemo, useRef, ReactElement, useCallback } from 'react';
import { Table } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
import type { SortableContainerProps, SortEnd } from 'react-sortable-hoc';
import { DeleteOutlined, HolderOutlined } from '@ant-design/icons';
import { arrayMoveImmutable } from 'array-move';
import { getMessage, TextWidget } from '@inbiz/react';

const DragHandle = SortableHandle(() => (
  <HolderOutlined className="dragHandle" />
)) as unknown as () => ReactElement;

const SortableItem = SortableElement((props: React.HTMLAttributes<HTMLTableRowElement>) => (
  <tr {...props} />
));
const SortableBody = SortableContainer((props: React.HTMLAttributes<HTMLTableSectionElement>) => (
  <tbody {...props} />
));

function Editable<T extends { IndexFieldName: string }, K extends keyof T>({
  value,
  onChange,
  columns,
  rowKey,
  footer,
}: {
  rowKey: K;
  value: T[];
  onChange: (value: T[] | (Pick<T, K> & { type: 'delete' | 'add' })) => void;
  columns: ColumnsType<T>;
  footer?: () => ReactElement;
}) {
  const refValue = useRef(value);
  refValue.current = value;
  const onSortEnd = useCallback(({ oldIndex, newIndex }: SortEnd) => {
    if (oldIndex !== newIndex) {
      const newData = arrayMoveImmutable(refValue.current.slice(), oldIndex, newIndex).filter(
        (el) => !!el,
      );
      onChange(newData);
    }
  }, []);
  const DraggableBodyRow: React.FC<any> = useCallback(
    ({ className, style, ...restProps }) => {
      const index = value.findIndex((x) => x[rowKey] === restProps['data-row-key']);
      //@ts-ignore
      return <SortableItem index={index} {...restProps} />;
    },
    [value?.map((item) => item.IndexFieldName).join(',')],
  );
  const sortableRef: any = useRef();
  const DraggableContainer = useCallback(
    (props: SortableContainerProps) => (
      //@ts-ignore
      <SortableBody
        useDragHandle
        disableAutoscroll
        helperClass="row-dragging"
        onSortEnd={onSortEnd}
        helperContainer={() => {
          return sortableRef.current?.container || document.body;
        }}
        ref={sortableRef}
        {...props}
      />
    ),
    [value?.map((item) => item.IndexFieldName).join(',')],
  );

  const newColumns = useMemo(() => {
    return [
      ...columns,
      {
        title: getMessage('SearchResultEngine.operation'),
        dataIndex: 'operation',
        width: 250,
        render: (_value: any, record: T) => {
          return (
            <div className="editable-operations">
              {record?.IndexFieldName && <a
                onClick={() =>
                  onChange({
                    [rowKey]: record[rowKey],
                    type: 'delete',
                  } as Pick<T, K> & { type: 'delete' | 'add' })
                }
              >
                <DeleteOutlined />
                <TextWidget>SearchResultEngine.delete</TextWidget>
              </a>}
              <DragHandle />
            </div>
          );
        },
      },
    ];
  }, [columns]);
  return (
    <Table
      pagination={false}
      dataSource={value}
      columns={newColumns}
      rowKey={rowKey as string}
      size="small"
      bordered
      className="editTable"
      components={{
        body: {
          wrapper: DraggableContainer,
          row: DraggableBodyRow,
        },
      }}
      footer={footer}
    />
  );
}

export default Editable;
